# -*- coding: utf-8 -*-


# cmap2owl -- Helper application to convert from concept maps to OWL ontologies
# Copyright (c) 2008-2013  Rodrigo Rizzi Starr
#  
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#  
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#  
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.


'''
Implements a parser to read a CXL file (used by CMapTools to export a concept
map) into an independent representation, as defined in the file
independentRepresentation.

# NOTE: This version ignores meta tags, as author, etc. 

@author: Rodrigo Rizzi Starr
@copyright: Copyright © 2008-2013 Rodrigo Rizzi Starr
@license: MIT License
@contact: rodrigo.starr@gmail.com
'''


from independentRepresentation import Graph, Point
from graphicalElement import GraphicalElement, Connection
from XMLParser import XMLParser, StateHandler, DummyStateHandler
from log import *
log.debug('Loaded...')


class CXLReader(XMLParser):
    '''A parser to a CXL file. This class is initialized with a file name, them,
       on calling the method parse(), it returns a Graph instance containing the
       representation of the graph in the file.
    '''
   
    def __init__(self, fileName):
        '''Initializes a Parser for a CXL file. It uses some auxiliary classes
           as StateHandlers. The baseState is the HandleCmap handler
        '''
        
        self.graph = Graph()
        baseState = HandleCmap(self.graph)
      
        XMLParser.__init__(self, fileName, baseState)
      

class HandleCmap(DummyStateHandler):
    'Handles the root tag in a CXL file'
   
    def __init__(self, graph):
        stateTransitions = {'res-meta': DummyStateHandler({}),
                            'map': HandleMap(graph),
                         }
        DummyStateHandler.__init__(self, stateTransitions, graph)

        
class HandleMap(StateHandler):
    'Handle the map tag'
    def __init__(self, graph):
        stateTransitions = {
         'concept-list': HandleConceptList(graph),
         'linking-phrase-list': HandleLinkingPhraseList(graph),
         'connection-list': HandleConnectionList(graph),
         'resource-group-list': DummyStateHandler({}),
         'concept-appearance-list': HandleConceptAppearanceList(graph),
         'linking-phrase-appearance-list': 
                    HandleLinkingPhraseAppearanceList(graph),
         'connection-appearance-list': HandleConnectionAppearanceList(graph),
         'style-sheet-list': HandleStyleSheetList(graph),
         'extra-graphical-properties-list': DummyStateHandler({}),
        }
        StateHandler.__init__(self, stateTransitions, graph)

    def ConsumeAttrs(self, attrs):
        'Handle the attributes of the map tag'
        self.data.graphicalProperties = Point(int(attrs['width']),
                                              int(attrs['height']))
      
      
class HandleConceptList(StateHandler):
    'Parses the concepts list'
    def __init__(self, graph):
        stateTransitions = {'concept': HandleConcept(graph), }
        StateHandler.__init__(self, stateTransitions, graph)

        
class HandleConcept(StateHandler):
    'Parses concepts'
    
    def __init__(self, graph):
        StateHandler.__init__(self, {}, graph)
      
    def ConsumeAttrs(self, attrs):
        'Define concepts'
        self.data.addNode(label=attrs['label'],
                          elId=self.data.createValidId(attrs['id']))
      

class HandleLinkingPhraseList(StateHandler):
    'Parses linking phrases list'
    def __init__(self, graph):
        stateTransitions = {'linking-phrase': HandleLinkingPhrase(graph), }
        StateHandler.__init__(self, stateTransitions, graph)

        
class HandleLinkingPhrase(StateHandler):
    'Parses linking phrases'
    def __init__(self, graph):
        StateHandler.__init__(self, {}, graph)

    def ConsumeAttrs(self, attrs):
        'Reads a linking phrase attribute'
        self.data.addArc(label=attrs['label'].strip(),
                                elId=self.data.createValidId(attrs['id']))

        
class HandleConnectionList(StateHandler):
    'Parses the connection list'
    def __init__(self, graph):
        stateTransitions = {'connection': HandleConnection(graph), }
        StateHandler.__init__(self, stateTransitions, graph)

        
class HandleConnection(StateHandler):
    'Parses the connections'
    def __init__(self, graph):
        StateHandler.__init__(self, {}, graph)

    def ConsumeAttrs(self, attrs):
        'Saves the data for the connections'
        g = self.data
        elFrom = g.getElementById(self.data.createValidId(attrs['from-id']))
        elTo = g.getElementById(self.data.createValidId(attrs['to-id']))
        self.data.connect(elFrom, elTo, attrs['id'])

        
class HandleConceptAppearanceList(DummyStateHandler):
    'Parses the appearance list for the concepts'
    def __init__(self, graph):
        stateTransitions = {'concept-appearance': HandleAppearance(graph,
                                                                   'Concept'),}
        DummyStateHandler.__init__(self, stateTransitions, graph)

        
class HandleLinkingPhraseAppearanceList(DummyStateHandler):
    'Parses the appearance list for the linking phrases'
    def __init__(self, graph):
        stateTransitions = {'linking-phrase-appearance': HandleAppearance(graph,
                                                            'LinkingPhrase'),}
        DummyStateHandler.__init__(self, stateTransitions, graph)

        
class HandleAppearance(StateHandler):
    'Read the appearance'
    def __init__(self, graph, kind):
        StateHandler.__init__(self, {}, graph)
        self.kind = kind

    def ConsumeAttrs(self, attrs):
        'Generate a graphicalProperties of the correct kind'
        g = self.data
        el = g.getElementById(attrs['id'])
        width = int(attrs['width'])
        height = int(attrs['height'])
        factory = GraphicalElement.factory(self.kind)
        el.graphicalProperties = factory(int(attrs['x']) - width/2,
                                         int(attrs['y']) - height/2,
                                         width,
                                         height,
                                         el,
                                        )

        
class HandleConnectionAppearanceList(DummyStateHandler):
    'Reads the control points of the connection'
    def __init__(self, graph):
        stateTransitions = {'connection-appearance':
                                        HandleConnectionAppearance(graph),}
        DummyStateHandler.__init__(self, stateTransitions, graph)

        
class HandleConnectionAppearance(StateHandler):
    'Reads the appearance of a connection'
    def __init__(self, graph):
        self.cpHandler = HandleControlPoint(graph)
        stateTransitions = {'control-point': self.cpHandler, }
        
        StateHandler.__init__(self, stateTransitions, graph)

    def ConsumeAttrs(self, attrs):
        'Generate a graphicalProperties of the correct kind'
        
        el = self.data.getElementById(attrs['id'])
        graphConnection = Connection(el)
        try:
            graphConnection.type = attrs['type']
        except KeyError:
            pass
        
        self.cpHandler.el = graphConnection
        
        el.graphicalProperties = graphConnection

        
class HandleControlPoint(StateHandler):
    'Reads each control point in the control point list'
    def __init__(self, graph):
        self.el = None
        StateHandler.__init__(self, {}, graph)

    def ConsumeAttrs(self, attrs):
        'Generate a graphicalProperties of the correct kind'
        self.el.controlPoints.append( (int(attrs['x']), int(attrs['y'])) )

        
class HandleStyleSheetList(DummyStateHandler):
    'Ignore the style sheets'
    def __init__(self, graph):
        DummyStateHandler.__init__(self, {}, graph)

        
if __name__ == '__main__':
    p = CXLReader('test/Concept maps - By Novak.cxl')
    p.parse()
    try:
        print p.getData()
    except UnicodeEncodeError, e:
        a = e
        raise
   
